#ifndef GBFREETYPE_H
#define GBFREETYPE_H

#ifdef GB_GL
#include <windows.h>
#include <glee.h>
#include <gl.h>
#elif GB_DX
#include <d3dx9.h>
#endif

#include "MeshComponents.h"
#include <windows.h>

#include <ft2build.h>  
#include <freetype/freetype.h>  
#include <freetype/ftglyph.h>  
#include <freetype/ftoutln.h>  
#include <freetype/fttrigon.h> 

#include <deque>
#include <map>

// This number determines what char-array range is used for example: 0 - GB_NUM_CHARS in an ascii table
#ifndef GB_NUM_CHARS
#define GB_NUM_CHARS 128
#endif

// WARNING: Changing this number (>max) could cause high memory usage
#ifndef GB_MAX_FONT_SIZE
#define GB_MAX_FONT_SIZE 128
#endif

// WARNING: Changing this number may render your text unreadable by the human eye
#ifndef GB_MIN_FONT_SIZE
#define GB_MIN_FONT_SIZE 7
#endif

class GBFreeType
{
public:
	struct GBCharMesh
	{
		vec2 texturePad;
		MeshComponent::Triangle triangles[2];
		vec3 vertices[4];
		vec3 texCoords[4];
	};

private:
	struct GBFace
	{
		bool used;
		long pt;
		unsigned nTextures[GB_NUM_CHARS];
		int nLists[GB_NUM_CHARS];
		unsigned long ulWidth[GB_NUM_CHARS];
		unsigned long ulHeight[GB_NUM_CHARS];
		FT_Face face;
		GBCharMesh mesh[GB_NUM_CHARS];

		GBFace() : used(1), pt(0) 
		{
			memset(nTextures, 0, GB_NUM_CHARS * sizeof(nTextures[0]));
			memset(nLists, -1, GB_NUM_CHARS * sizeof(nLists[0]));
			memset(ulWidth, 0, GB_NUM_CHARS * sizeof(ulWidth[0]));
			memset(ulHeight, 0, GB_NUM_CHARS * sizeof(ulHeight[0]));
		}
	};

private:
	FT_Library m_library;
	std::deque<GBFace> m_faces;	

	// Typedefs:
	typedef std::deque<GBFace>::iterator FacesIter;
	typedef std::deque<GBFace>::const_iterator FacesConstIter;

	int CacheGlyph(GBFace& face, unsigned char ch);

public:
	GBFreeType();
	~GBFreeType();

	// Automatically called in the constructor
	void Initialize();

	void CacheFace(const int nID, unsigned char begin = ' ', unsigned char end = GB_NUM_CHARS);

	// Automatically called in the destructor
	void Shutdown();

	void Render(const char* szText, const int nID);
	int CreateFace(const char* szFilename, long pt);
	void DestroyFace(const int nID);

	int GetPtSize(const int nID) const;
	float GetGlyphWidth(const int nID, const char ch) const;
	float GetGlyphHeight(const int nID, const char ch) const;
	float GetTextWidth(const int nID, const char* szText) const;
	float GetTextHeight(const int nID, const char* szText) const;
	const GBCharMesh* GetGlyphMesh(const int nID, const char ch) const;

	bool IsAvailable(const int nID) const;
};

#endif